<!doctype html>
<html lang="en">

	<head>
		<meta charset="utf-8">

		<title>'Embedding' a Meta State Machine - Workshop</title>

		<meta name="description" content="'Embedding' a Meta State Machine">
		<meta name="author" content="Kris Jusiak">

		<meta name="apple-mobile-web-app-capable" content="yes">
		<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">

		<link rel="stylesheet" href="css/reveal.css">
    <link rel="stylesheet" href="css/theme/league.css" id="theme">

		<!-- Code syntax highlighting -->
    <link rel="stylesheet" href="lib/css/zenburn.css">

		<!-- Printing and PDF exports -->
		<script>
			var link = document.createElement( 'link' );
			link.rel = 'stylesheet';
			link.type = 'text/css';
			link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
			document.getElementsByTagName( 'head' )[0].appendChild( link );
		</script>

		<!--[if lt IE 9]>
		<script src="lib/js/html5shiv.js"></script>
		<![endif]-->
	</head>

	<body>

		<div class="reveal">
			<div class="slides">

          <section data-markdown=""
                   data-separator="^====+$"
                   data-separator-vertical="^----+$"
                   data-notes="^Note:">
					<script type="text/template">

<img src="images/embo-logo.png" style="width: 20%; background:none; border:none; box-shadow:none;" />

# 'Embedding' a Meta State Machine

Kris Jusiak, Quantlab Financial

---

#### [kris@jusiak.net](mailto:kris@jusiak.net) | [@krisjusiak](https://twitter.com/krisjusiak) | [linkedin.com/in/kris-jusiak](https://www.linkedin.com/in/kris-jusiak)

==============================================================================

### Agenda - Introduction

* Motivation

* UML-2.5
  * State Machine

* [Boost].SML
  * Overview
  * Goals
  * Design
  * Benchmark

----

### Agenda - Workshop - Basic

* Connection State Machine
  * Hello World
    * Events/States
  * Transitions
    * Actions/Guards
  * Dependencies
  * Logging/Debugging/Testing
  * Runtime dispatching
  * Performance tuning
  * Diagrams generation

* Exercise

----

### Agenda - Workshop - Advanced

* System State Machine
  * Composite/Sub states
  * History
  * Defer/Process
  * Orthogonal Regions

* Exercise

==============================================================================

### Workshop - materials

<img src="images/qr_code.jpg" style="width: 30%; background:none; border:none; box-shadow:none;" />

http://boost-experimental.github.io/sml/embo-2018

==============================================================================

### Motivation

```gherkin
Feature: Connection

  Scenario: Establish connection 1/2
    Given I have a connection handler
     When I receive a connect request
     Then I should establish connectivity

  Scenario: Establish connection 2/2
    Given I have established connectivity
     When I receive a established ack
      And The ack is valid
     Then I'm connected
```

----

### Motivation - naive implementation

```cpp
void establish() {}
bool is_valid(const void*);
```

```cpp
void handle(int id, const void* message) {
  static bool is_connected = false;
  static bool is_connecting = false;

  if (id == 0 && !is_connected && !is_connecting) {
    establish();
    is_connecting = true;
  } else if (id == 1
      && is_connecting && !is_connected && is_valid(message)) {
    is_connecting = false;
    is_connected = true;
  } /* else if
      ...
    */
}
```

----

### Motivation - naive implementation

<img src="images/debug.jpg" style="width: 50%; background:none; border:none; box-shadow:none;" />

> Maintenance nightmare (Spaghetti code)

----

### Motivation - hand written state machine

```cpp
struct Connection {
  enum { CONNECT, ESTABLISHED, PING, TIMEOUT, DISCONNECT };
  void handle(int id, const void* message) {
    switch (state) {
      case Disconnected:
        switch (id) {
          case CONNECT: establish(); state = Connecting; break;
        }
      case Connecting:
        switch (id) {
          case ESTABLISHED: state = Connected; break;
        }
      /*case...*/
    }
  }
```
<!-- .element: style="margin-left:0%; width:100%" -->

```cpp
private:
  bool is_valid(const void*) const;
  void establish();
  enum { Disconnected, Connecting, Connected } state = Disconnected;
};
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

### Motivation - hand written state machine

<img src="images/debugging.jpg" style="width: 35%; background:none; border:none; box-shadow:none;" />

> Not scalable - Fusilli code (A spin to make bad code look good)

==============================================================================

### Introduction - UML-2.5 - State Machine

<img src="images/uml-2.5.png" style="width: 50%; background:none; border:none; box-shadow:none;" />

https://www.omg.org/spec/UML/2.5.1/PDF

----

### Introduction - UML-2.5 - State Machine

![Connection](images/connection.png)

| |
|-|
|Transition - Unified Modeling Language (UML)|
|<center>![Transition](images/transition.png)</center>|

==============================================================================

### [Boost].SML - State Machine Language

https://github.com/boost-experimental/sml

----

### [Boost].SML - State Machine Language

<iframe class="stretch" data-src="http://boost-experimental.github.io/sml" />

----

### [Boost].SML - Overview

* One header
  * `sml.hpp` - 2k LOC
* Neither Boost nor STL is required
* No 'virtual's (-fno-rtti)
* No exceptions (-fno-exceptions)
* Supported compilers (C++14)
 * [Clang-3.4+](https://travis-ci.org/boost-experimental/sml), [XCode-6.1+](https://travis-ci.org/boost-experimental/sml), [GCC-5.2+](https://travis-ci.org/boost-experimental/di), [MSVC-2015+](https://ci.appveyor.com/project/krzysztof-jusiak/sml)

----

### [Boost].SML - Goals

* UML-2.5 standard compliant
* Declarative
  * Neither code generation nor macros
* Quick compilation-times
  * Much faster than Boost.MSM/Boost.Statechart
* No run-time overhead
  * Don't pay for what you don't use!
* Minimal memory usage
  ```cpp
  sizeof(SM) == 1b
  ```
* Small executable size
* Extensible/Customizable

----

### [Boost].SML - Features

* UML (2.5)
  * Transition
    * Anonymous, Internal, External, Self transition
    * Guard, Action
  * Unexpected, Deffered, Any event
  * State
    * Entry/Exit Actions, Initial, Terminate state
    * Composite/Sub state
      * Explicit entry/exit, ~~Fork~~
      * Shallow History, Deep History
  * Orthogonal regions

----

### [Boost].SML - Features

* Non-UML
  * Logging, State visitor, Diagrams, Run-time dispatch

----

### [Boost].SML - Design

<img style="background:none; border:none; box-shadow:none;" src="images/design.png" width="45%" />

| Component    | Description |
| ------------ | ----------- |
| Front-End  | Transition Table Domain Specific Language |
| Back-End   | State Machine implementation details |

----

### [Boost].SML - [Benchmark](https://github.com/boost-experimental/sml/tree/master/benchmark/complex)

![Benchmark](images/benchmark.png)

| Events | States | Transitions | Process Events |
| ------ | ------ | ----------- | -------------- |
| 50 | 50 | 50 | 1'000'000 |

----

### [Boost].SML - [Benchmark](https://github.com/boost-experimental/sml/tree/master/benchmark/complex)

#### Main
```cpp
int main() {
  for (auto i = 0; i < 1'000'000; ++i) {
    if (rand() % 2) sm.process_event(e1());
    if (rand() % 2) sm.process_event(e2());
    if (rand() % 2) sm.process_event(e3());
    ...
    if (rand() % 2) sm.process_event(e100());
  }
}
```

#### CXXFLAGS
```
$CXX -std=c++1z -O3 -flto -fno-exceptions -DNDEBUG benchmark.cpp
```

----

### [Boost].SML - [Benchmark](https://github.com/boost-experimental/sml/tree/master/benchmark/complex)

<img style="background:none; border:none; box-shadow:none;" src="images/benchmark_results.png" width="140%" />

==============================================================================

### Workshop - Basic

==============================================================================

### Hello World - Connection

![](images/sm_example.png)

----

#### [Boost].SML basic setup

```cpp
// one header; neither STL nor Boost required
#include <boost/sml.hpp>

// convenient alias
namespace sml = boost::sml;
```

----

#### State represents current location of the flow

| | |
|-|-|
| ![](images/disconnected_state.png) | ![](images/connecting_state.png) |

```cpp
// On the fly declaration (default)
using namespace sml;
"Diconnected"_s
```

```cpp
// Standard declaration
sml::state<class Connecting>{};
```

----

#### Initial State tells the state machine where to start

![](images/initial_state.png)

```cpp
// Star indicates that SM should from here
* "Disconnected"_s
```

----

#### Event is a unique type which will be processed by the state machine

```cpp
struct connect { };
```

----

#### Transition Table is a DSL describing the behaviour

![](images/sm_example.png)

```cpp
* "Disconnected"_s + event<connect> = "Connecting"_s
```

----

#### State Machine glues the front-end and the back-end

```cpp
struct Connection {
  auto operator()() const {
    using namespace sml;
    return make_transition_table(
      * "Disconnected"_s + event<connect> = "Connecting"_s
    )
  }
};
```

```cpp
// Creates a state machine
sml::sm<Connection> sm;
```

----

#### Process event is the client interface with the state machine


```cpp
// Process incoming events
sm.process_event(connect{});
```

----

#### Hello World - Connection

<iframe class="stretch" data-src="https://godbolt.org/g/4ATTGG" />

==============================================================================

### Transitions - Connection

![](images/transition_table.png)

----

#### Transitions - Connection

```cpp
* -> Disconnected : connect / establish              -> Connecting
```
<!-- .element: style="margin-left:0%; width:100%" -->

```cpp
     Connecting   : established                      -> Connected
```
<!-- .element: style="margin-left:0%; width:100%" -->

```cpp
     Connected    : ping [ is_valid ] / resetTimeout
```
<!-- .element: style="margin-left:0%; width:100%" -->

```cpp
     Connected    : timeout                          -> Connecting
```
<!-- .element: style="margin-left:0%; width:100%" -->

```cpp
     Connected    : disconnect                       -> Disconnected
```
<!-- .element: style="margin-left:0%; width:100%" -->

<center>![Transition](images/transition.png)</center>

----

#### Guard is a functor called before the optional transition (MUST return boolean)

```cpp
// Empty guard
const auto is_valid = [] { return true; };
```

```cpp
// Guard can take event as an optional parameter
const auto is_valid = [](const auto& event) {
  return event.id > 0;
};
```

----

#### Action is a functor called on transition (MUST not return)

```cpp
// Empty action
const auto resetTimeout = [] { };
```

```cpp
// Action can take event as an optional parameter
const auto resetTimeout = [](const auto& event) { };
```

----

#### Transitions DSL (Domain Specific language)

<center>![Transition](images/transition.png)</center>

```cpp
SourceState + event [ guard ] / action = DestinationState
                                     ^
                                     |
                                    1. DestinationState + on_exit
                                    2. SourceState + on_entry
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

#### Transitions DSL (Domain Specific language)

* Guard is optional and can be combined using logic operations
  ```cpp
  [ guard1 and not guard2 ]
  ```

* Action is optional and can be sequenced using a comma operator
  ```cpp
  (action1, action2)
  ```

* Event is optional - Anonymous transition
  ```cpp
  SourceState + [ guard ] / action = DestinationState
  ```

* DestinationState is optional - Internal transition
  ```cpp
  SourceState + [ guard ] / action
  ```

----

#### Transitions DSL (Domain Specific language) - Connection

<center>![Transition](images/simple_transition.png)</center>

```cpp
"Connected"_s + event<ping> [ is_valid ] / resetTimeout
```

----

#### Transitions - Connection

<iframe class="stretch" data-src="https://godbolt.org/g/8YP8Ac" />

----

#### Transitions - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/dQI7zeVdyLsrvI2t" />

==============================================================================

### Dependencies

----

#### External dependencies are shared between state machines

```cpp
class Sender { ... };  // Instance per application
class Context { ... }; // Instance per application
```

```cpp
const auto is_valid =
  [](const Context& ctx, const auto& event) {
    return ctx.valid(event.id);
  };
```

```cpp
const auto establish = [](Sender& sender, Context& ctx) {
  sender.send(ctx.ip, "establish");
};
```

----

#### External dependencies are injected into guards/actions

```cpp
const auto is_valid = [](const Context& ctx, const auto& event) {
                               /                 \
int main() {                  /                   ----------------\
  Context ctx{...};          /                                    |
  Sender sender{...};       /                                     |
  sml::sm<Connection> sm{ctx, sender}; // order is not specified  |
                                                                  /
  sm.process_event(ping{true}); ----------------------------------
}
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

#### External dependencies

<iframe class="stretch" data-src="https://godbolt.org/g/Vhy1kY" />

----

#### Per State machine dependencies are specific to the state machine

```cpp
const auto establish = [](const auto& address) {
  return [&address](Sender& sender) {
    sender.send(address, "establish");
  };
};
```
<!-- .element: style="margin-left:-3%; width:115%" -->

```cpp
struct Connection {
  const char* const address{}; // local dependency injected

  auto operator()() const {
    using namespace sml;
    return make_transition_table(
      * "Disconnected"_s + event<connect> / establish(address) = "Connecting"_s,
      // ...
    );
  }
};
```
<!-- .element: style="margin-left:-3%; width:115%" -->

----

#### Per State machine dependencies are initialized by the constructor

```cpp
int main() {
  Context ctx{...};
  Sender sender{...};
  std::array connections = {
    sml::sm<Connection>{Connection{"127.0.0.1"}, ctx, sender},
    sml::sm<Connection>{Connection{"127.0.0.2"}, ctx, sender},
    sml::sm<Connection>{Connection{"127.0.0.3"}, ctx, sender},
    sml::sm<Connection>{Connection{"127.0.0.4"}, ctx, sender}
  };

  connections[0].process_event(connect{});
  connections[1].process_event(established{});
  connections[2].process_event(ping{42});
  connections[3].process_event(disconnect{});
}
```

----

#### Per State machine dependencies

<iframe class="stretch" data-src="https://wandbox.org/permlink/mdPk0IS2QNwqcMjH" />

----

#### Per Guard/Action dependencies are local to functors

```cpp
auto establish =
  [max_retries = 10](const auto& address) mutable {
    return [&](Sender& sender, Context& ctx) {
      max_retries -= sender.send(address, "establish");

      if (!max_retries) {
        ctx.log("Can't send request!");
        max_retries = {};
      }
    };
  };
```

----

#### Per Guard/Action dependencies

<iframe class="stretch" data-src="https://wandbox.org/permlink/VpZdfJngvrl6vNZY" />

----

#### Per State dependencies are used by guards/actions

```cpp
auto establish =
  [max_retries = 10](const auto& address, auto& data) mutable {
    return [&](Sender& sender, Context& ctx, auto event) {
      max_retries -= sender.send(address, "establish");

      if (!max_retries) {
        ctx.log("Can't send request!");
        max_retries = {};
      }

      data = event.id; // per state storage
    };
  };
```

----

#### Per State dependencies limit the required size

```cpp
struct Connection {
  explicit Connection(std::string_view address) : address_{address} {}

  auto operator()() {
    using namespace sml;
    return make_transition_table(
      * "Disconnected"_s + event<connect> / establish(address_, data_) = "Connecting"_s,
      // ...
    );
  }

 private:
  std::string_view address_{};
  std::variant<int /*etc...*/> data_{}; // Type safe union storage per state
};
```
<!-- .element: style="margin-left:-12%; width:125%" -->

----

#### Per State dependencies

<iframe class="stretch" data-src="https://wandbox.org/permlink/gWjVg0gJTpdhDW4B" />

----

### [Boost].DI automates dependency injection

https://github.com/boost-experimental/di

----

#### Inject State Machine dependencies with [Boost].DI

```cpp
// Manual Dependency Injection
Context ctx{};
Sender sender{};
sml::sm<Connection> sm{ctx, sender};
```

```cpp
// Automatic Dependency Injection with [Boost].DI
auto injector = di::make_injector();
injector.create<sml::sm<Connection>>();
```

==============================================================================

### Logging/Debugging/Error handling

----

#### Logging - my_logger

```cpp
template <class SM, class TEvent> void log_process_event(const TEvent&) {
  printf("[%s][process_event] %s\n", name<SM>(), name<TEvent>());
}
```
<!-- .element: style="margin-left:-11%; width:122%" -->

```cpp
template <class SM, class TSrcState, class TDstState>
void log_state_change(const TSrcState& src, const TDstState& dst) {
  printf("[%s][transition] %s -> %s\n", name<SM>(), src.c_str(), dst.c_str());
}
```
<!-- .element: style="margin-left:-11%; width:122%" -->

```cpp
template <class SM, class TGuard, class TEvent>
void log_guard(const TGuard&, const TEvent&, bool result) {
  printf("[%s][guard] %s %s %d\n", name<SM>(), name<TGuard>(), name<TEvent>(), result);
}
```
<!-- .element: style="margin-left:-11%; width:122%" -->

```cpp
template <class SM, class TAction, class TEvent>
void log_action(const TAction&, const TEvent&) {
  printf("[%s][action] %s %s\n", name<SM>(), name<TAction>(), name<TEvent>());
}
```
<!-- .element: style="margin-left:-11%; width:122%" -->

----

#### Logging - my_logger - Connection

```cpp
my_logger logger{};
sml::sm<Connection, sml::logger<my_logger>> sm{logger};
```

----

#### Logging - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/6aWV4s7TMx2d793e" />

----

#### Debugging

* Verify the current state
  ```cpp
  using namespace sml;
  assert(connection.is("Connecting"_s));
  ```
<!-- .element: style="margin-left:-3%; width:105%" -->

* Visit current states
  ```cpp
  connection.visit_current_states([](auto state) {
    std::cout << state.c_str() << std::endl;
  });
  ```
<!-- .element: style="margin-left:-3%; width:105%" -->

----

#### Debugging - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/dpxXjc3NQQ4H0GVz" />

----

### Error handling

----

#### Terminate state finish the state machine (graceful shutdown)

![](images/terminate_state.png)

```cpp
sml::X // sml::terminate_state
```

----

#### Error handling

* Unexpected events
  ```cpp
  "Disconnected"_s + unexpected_event<_> = X
  ```
  <!-- .element: style="margin-left:0%; width:100%" -->

* Exceptions (only if not compiled with -fno-exceptions)
  ```cpp
  "Disconnected"_s + exception<std::runtime_error> / [] { cleanup(); },
  "Disconnected"_s + exception<_> = X // other exception -> terminate
  ```
  <!-- .element: style="margin-left:0%; width:100%" -->

----

#### Error Handling - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/hjcypH2KAYhMR1WW" />

==============================================================================

### Runtime Dispatching

----

#### Runtime Dispatching requires type/data conversion - Connection

```cpp
struct connect : sml::utility::id<0> {};
struct ping    : sml::utility::id<1> {
  explicit ping(const void* msg) // convert dynamic data
     : valid{msg}
  { }

  bool valid{};
};
struct established : sml::utility::id<2> {};
struct timeout     : sml::utility::id<3> {};
struct disconnect  : sml::utility::id<4> {};
```

----

#### Runtime Dispatching - Connection

```cpp
#include <boost/sml/utility/dispatch_table.hpp>
```

```cpp
int main() {
  sml::sm<Connection> connection{};

  auto dispatch = sml::utility::make_dispatch_table<
    void*,        // dynamic data type
    0,            // min dynamic id
    4,            // max dynamic id
  >(connection);  // generates a jump table

  dispatch(nullptr, 0);      // connect
  dispatch(nullptr, 2);      // established
  int data{};
  dispatch((void*)&data, 1); // ping
  dispatch(nullptr, 4);      // disconnect
}
```

----

#### Runtime Dispatching - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/gmRFkmGHi9MTnPRh" />

==============================================================================

### Performance tuning

----

#### Policies allow to change State Machine implementation at compile time

```cpp
// Don't pay for what you don't use!
sml::sm<Connection, Policies...> sm{};
```

----

#### Thread safe policy enables/disabled thread safety

```cpp
sml::sm<Connection, sml::thread_safe<std::mutex>> sm{};
```

----

#### Exception handling policy requires a compilation flag

```
Exception handling is only available if NOT compiled with
  `-fno-exceptions` or
  `BOOST_SML_DISABLE_EXCEPTIONS`
```

----

#### Dispatch policy changes event dispatching strategy

| Name | POLICY |
| - | - |
| Jump Table | `jump_table` |
| Switch | `switch_stm` |
| If/else | `branch_stm` |
| Fold expressions | `fold_expr` |

```cpp
sml::sm<Connection, sml::dispatch<sml::back::policies::POLICY>> sm{};
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

#### Front-End - Transition Table

```cpp
static_assert(std::is_same<
  decltype(
    make_transition_table( // front-end
      * "Disconnected"_s + connect / establish = "Connecting"_s,
        "Connecting"_s   + established         = "Connected"_s
    )
  ),
  transition_table< // back-end
    // --------------------------------------------------------------------------------- //
    //         src_state              dst_state            event        guard   action   //
    // --------------------------------------------------------------------------------- //
    transition<state<"Disconnected">, state<"Connecting">, connect,     always, establish>,
    transition<state<"Connecting">,   state<"Connected">,  established, always, none>
  >
>{});
```
<!-- .element: style="margin-left:-13%; width:125%" -->

----

#### Back-End - Generated at Compile Time Mapping per Event and State

#### mappings_t
```cpp
pair<connect,
  type_list<
    transitions<
      transition<state<"Disconnected">, state<"Connecting">, connect, always, establish>
    >,
    transitions<>, // Connecting (unexpected event)
    transitions<>  // Connected  (unexpected event)
  >
>
```
<!-- .element: style="margin-left:-13%; width:125%" -->

```cpp
pair<established,
  type_list<
    transitions<>, // Disconnected (unexpected event)
    transitions<
      transition<state<"Connecting">, state<"Connected">,  established, always, none>
    >,
    transitions<>  // Connected (unexpected event)
  >
>
```
<!-- .element: style="margin-left:-13%; width:125%" -->

----

#### Dispatch policy - Process Event

```cpp
template<class TransitionTable>
class sm {
 public:
  constexpr void process_event(const TEvent& event) {
    dispatch_policy::dispatch(
      current_state_,
      event,
      typename TransitionTable::states{}
    );
  }

 private:
  state_t current_state_{};
};
```

----

#### Dispatch policy - jump table

```cpp
struct jump_table {
  template <class TEvent, class... TStates>
  constexpr auto dispatch(State &current_state,
                          const TEvent &event,
                          type_list<TStates...>) {
    using dispatch_table_t = bool (*)(const TEvent&, State &);
    constexpr static dispatch_table_t dispatch_table[] = {
      &mappings_t<TStates>::template execute<TEvent>...
    };
    return dispatch_table[current_state](event);
  }
};
```

----

#### Dispatch policy - jump table

<iframe class="stretch" data-src="https://godbolt.org/g/BKHgh9" />

----

#### Dispatch policy - switch

```cpp
struct switch_stm {
  template <class TEvent>
  constexpr auto dispatch(State &, const TEvent &, type_list<>) { }

  template <class TEvent, class TState, class... TStates>
  constexpr auto dispatch(State &current_state,
                          const TEvent &event,
                          type_list<TState, TStates...>) {
    switch (current_state) {
      default: return dispatch(current_state, type_list<TStates...>{});
      case N: return mappings_t<TState>::template execute<TEvent>(event);
    }
  }
};
```
<!-- .element: style="margin-left:1%; width:105%" -->

----

#### Dispatch policy - switch

<iframe class="stretch" data-src="https://godbolt.org/g/zFF7LM" />

----

#### Dispatch policy - if/else

```cpp
struct branch_stm {
  template <class TEvent>
  constexpr auto dispatch(State &, const TEvent &, type_list<>) { }

  template <class TEvent, class TState, class... TStates>
  constexpr auto dispatch(State &current_state,
                          const TEvent &event,
                          type_list<TState, TStates...>) {
    return current_state == N
      ? mappings_t<TState>::template execute<TEvent>(event)
      : dispatch(current_state, event, type_list<TStates...>{});
  }
};
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

#### Dispatch policy - if/else

<iframe class="stretch" data-src="https://godbolt.org/g/cJvKYB" />

----

#### Dispatch policy - fold expressions

```cpp
struct fold_expr {
  template <auto... Ns, class TEvent, class... TStates>
  constexpr auto dispatch_impl(State &current_state,
                              index_sequence<Ns...>,
                              const TEvent &event,
                              type_list<TStates...>) {
    return ((current_state == Ns
      ? mappings_t<TStates>::template
          execute<TEvent>(event)
      : false
    ) || ...);
  }
};
```

----

#### Dispatch policy - fold expressions

<iframe class="stretch" data-src="https://godbolt.org/g/vzL8w4" />

----

#### Performance tuning - Dispatch policy

<iframe class="stretch" data-src="https://godbolt.org/g/bviBBB" />

==============================================================================

### Diagrams generation

----

#### PlantUML

```
@startuml connection.png
title Connection

[*]          -> Disconnected
Disconnected -> Connecting    : connect / establish
Connecting   -> Connected     : established
Connected    -> Connected     : ping [ is_valid ] / resetTimeout
Connected    -> Connecting    : timeout
Connected    -> Disconnected  : disconnect

@enduml
```

http://plantuml.com/state-diagram

----

#### Diagrams generation - Plant UML

```cpp
template <class T>
void dump_transition() noexcept {
  const auto src_state = msm::state<typename T::src_state>::c_str();
  const auto dst_state = msm::state<typename T::dst_state>::c_str();

  if (T::initial) {
    std::cout << "[*] -> " << src_state << std::endl;
  }

  std::cout << src_state << " -> " << dst_state << " : "
            << name<typename T::event>() << "["
            << name<typename T::guard>() << "] / "
            << name<typename T::action>();
}
```
<!-- .element: style="margin-left:0%; width:100%" -->

----

#### Diagrams generation - Plant UML - Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/IjvxJCLgAeoBo0GY" />

----

#### Diagrams generation - Plant UML - Connection

![diagrams](images/diagrams.png)

==============================================================================

### Exercise - Parser

![system](images/parser.png)

----

#### Exercise - Parser - Problem

<iframe class="stretch" data-src="https://wandbox.org/permlink/wUqf3AFpWN1r4TtA" />

----

#### Exercise - Parser - Example Solution

<iframe class="stretch" data-src="https://wandbox.org/permlink/rnAGopy8vvvkamgj" />

==============================================================================

### Workshop - Advanced

==============================================================================

### System State Machine

![system](images/system.png)

==============================================================================

### Composite/Sub states

----

### A state machine might be a State itself - Composite

![](images/composite_state.png)

```cpp
auto state = sml::state<Connection>;
```

----

### A state machine might be a State itself - Composite

* If composite state is active events are handled by it first

* When composite state didn't handle the event a top state machine is going to try to handle it

* When composite is reactivated - by default - the initial state is entered

----

### Composite/Sub states - System

![system](images/system_composite.png)

----

### Composite/Sub states - System

```cpp
class System {
  struct Connection; // Connection State Machine

 public:
  auto operator()() const {
    using namespace sml;
    return make_transition_table(
     * "Idle"_s          + event<power_up> [ has_battery and
                                             is_healthy ] / setup = state<Connection>,
       state<Connection> + event<suspend>                         = "Suspended"_s,
       "Suspended"_s     + event<resume>                          = state<Connection>
    );
  }
};
```
<!-- .element: style="margin-left:-11%; width:121%" -->

----

### Composite/Sub states - System

<iframe class="stretch" data-src="https://wandbox.org/permlink/B7U26WRnXUeCAvWm" />

==============================================================================

### History

----

### History enables reactivation of Last active state in composite state

![](images/history_state.png)

```cpp
"Disconnected"_s(H)
```

----

### History - System/Connection

![system](images/system_history.png)

----

### History - System/Connection

```cpp
struct Connection {
  auto operator()() const {
    using namespace sml;
    return make_transition_table(
      "Disconnected"_s(H) + event<connect> / establish = "Connecting"_s, // History
      // ...
    );
  }
};
```
<!-- .element: style="margin-left:-11%; width:120%" -->

```cpp
struct System {
  auto operator()() const {
    using namespace sml;
    return make_transition_table(
     * "Idle"_s          + event<power_up> [ has_battery and
                                             is_healthy ] / setup = state<Connection>,
       state<Connection> + event<suspend>                         = "Suspended"_s,
       "Suspended"_s     + event<resume>                          = state<Connection>
    );
  }
};
```
<!-- .element: style="margin-left:-11%; width:121%" -->

----

### History - System/Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/pz4xXdZwreWTwVZK" />

==============================================================================

### Defer/Process

----

### Defer saves unwanted events for later processing

![](images/defer.png)

```cpp
/ defer
```

----

### Defer/Process

* Defer events are used in a FIFO order
* Deferred events queue is checked on transition
* If deferred event can't be handled it stays in the queue
* [Boost].SML requires defer_queue policy
  ```cpp
  sml::sm<System, sml::defer_queue<std::deque>> sm{};
  ```

----

### Defer/Process - System/Connection

![system](images/system_defer.png)

----

### Defer/Process - System/Connection

```cpp
struct System {
  struct Connection; // ping can be handled by Connection

  auto operator()() const {
    using namespace sml;
    return make_transition_table(
     * "Idle"_s          + event<power_up> [ has_battery and
                                             is_healthy ] / setup = state<Connection>,
       state<Connection> + event<suspend>                         = "Suspended"_s,
       "Suspended"_s     + event<resume>                          = state<Connection>
       "Suspended"_s     + event<ping> / defer // can't handle it now
                                               // defer for later
    );
  }
};
```
<!-- .element: style="margin-left:-11%; width:121%" -->

----

### Defer/Process - System/Connection

<iframe class="stretch" data-src="https://wandbox.org/permlink/cdfjEtZYU56KmtPg" />

==============================================================================

### Orthogonal Regions

----

### Orthogonal Regions are executed in pseudo parallel fashion

![](images/orthogonal_regions.png)

----

### Orthogonal Regions - System

* Events ale always tried to be consumed by all active regions
  * Even if one region has handled an event
* [Boost].SML recognizes multiple initial states as separate regions
  ```cpp
  make_transition_table(
    * "region1.0"_s + event [ guard ] / action = "region1.1",
      "region1.0"_s + event [ guard ] / action = X,

    // ---------------------------------------------------- */

    * "region2.0"_s + event [ guard ] / action = "region2.1",
      "region2.0"_s + event [ guard ] / action = X
  )
  ```

----

### Orthogonal Regions - System

![system](images/system_orthogonal_regions.png)

----

### Orthogonal Regions - System

```cpp
struct System {
  struct Connection; // Connection State Machine
  auto operator()() const {
    return make_transition_table(
     * "Idle"_s          + event<power_up> [ has_battery and
                                             is_healthy ] / setup = state<Connection>,
       state<Connection> + event<suspend>                         = "Suspended"_s,
       "Suspended"_s     + event<resume>                          = state<Connection>
       "Suspended"_s     + event<ping> / defer
     // ----------------------------------------------------------------------------- //
     * "Watchdog"_s      + event<tick> / resetTimeout,
       "Watchdog"_s      + event<timeout>                         = X
    );
  }
};
```
<!-- .element: style="margin-left:-13%; width:125%" -->

----

### Orthogonal Regions - System

<iframe class="stretch" data-src="https://wandbox.org/permlink/XsWLNHTaEUPCuPw4" />

==============================================================================

### Exercise - System State Machine

![system](images/system.png)

----

### Exercise - System State Machine

* Dynamically convert command line arguments into events
  based on event id and produce `out` file with names of called actions

* Example
  ```
  ./a.out 5 0 2 1
  ```
  ```
  cat out
  setup
  establish
  ```
----

### Exercise - System State Machine - Problem

<iframe class="stretch" data-src="https://wandbox.org/permlink/eJCpChqZLqKivjCo" />

----

### Exercise - System State Machine - Example Solution

<iframe class="stretch" data-src="https://wandbox.org/permlink/82JwdSBHmLv7koU9" />

==============================================================================

### More Examples

---
[Hello World](http://boost-experimental.github.io/sml/examples/index.html#hello-world)

[Events](http://boost-experimental.github.io/sml/examples/index.html#events) |
[States](http://boost-experimental.github.io/sml/examples/index.html#states) |
[Actions Guards](http://boost-experimental.github.io/sml/examples/index.html#actions-guards) |
[Transitions](http://boost-experimental.github.io/sml/examples/index.html#transitions)

[Orthogonal Regions](http://boost-experimental.github.io/sml/examples/index.html#orthogonal-regions) |
[Composite](http://boost-experimental.github.io/sml/examples/index.html#composite) |
[History](http://boost-experimental.github.io/sml/examples/index.html#history)

[Error handling](http://boost-experimental.github.io/sml/examples/index.html#error-handling) |
[Logging](http://boost-experimental.github.io/sml/examples/index.html#logging) |
[Testing](http://boost-experimental.github.io/sml/examples/index.html#testing)

[Runtime Dispatcher](http://boost-experimental.github.io/sml/examples/index.html#runtime-dispatcher) |
[eUML Emulation](http://boost-experimental.github.io/sml/examples/index.html#euml-emulation) |
[Dependency Injection](http://boost-experimental.github.io/sml/examples/index.html#dependency-injection)

[SDL2 Integration](http://boost-experimental.github.io/sml/examples/index.html#sdl2-integration) |
[Plant UML Integration](http://boost-experimental.github.io/sml/examples/index.html#plant-uml-integration)

==============================================================================

### Summary

----

### If you like it or not, your code won't be stateless (most likely)

----

### Implicit/Hand written state machines are hard to
* Reason about
 * Maintain / Extend
 * Test

----

### State Machines are more than just simple transitions
* [UML-2.5](http://www.omg.org/spec/UML/2.5/)

----

### Leveraging Zero-cost libraries will boost your design and/or performance

==============================================================================

### Questions?

| [Boost].SML |  |
| ------- | ------------- |
| Documentation | http://boost-experimental.github.io/sml |
| Source Code | https://github.com/boost-experimental/sml |
| Try it online! | http://boost-experimental.github.io/sml/examples |
<!-- .element: style="margin-left:-13%; width:125%" -->

-

#### [kris@jusiak.net](mailto:kris@jusiak.net) | [@krisjusiak](https://twitter.com/krisjusiak) | [linkedin.com/in/kris-jusiak](https://www.linkedin.com/in/kris-jusiak)


					</script>
				</section>

			</div>
		</div>

		<script src="lib/js/head.min.js"></script>
		<script src="js/reveal.js"></script>

		<script>

			// Full list of configuration options available at:
			// https://github.com/hakimel/reveal.js#configuration
			Reveal.initialize({

        // Display controls in the bottom right corner
        controls: true,

        // Display a presentation progress bar
        progress: true,

        // Display the page number of the current slide
        slideNumber: true,

        // Push each slide change to the browser history
        history: true,

        // Enable keyboard shortcuts for navigation
        keyboard: true,

        // Enable the slide overview mode
        overview: true,

        // Vertical centering of slides
        center: true,

        // Enables touch navigation on devices with touch input
        touch: true,

        // Loop the presentation
        loop: false,

        // Change the presentation direction to be RTL
        rtl: false,

        // Turns fragments on and off globally
        fragments: false,

        // Flags if the presentation is running in an embedded mode,
        // i.e. contained within a limited portion of the screen
        embedded: false,

        // Flags if we should show a help overlay when the questionmark
        // key is pressed
        help: true,

        // Flags if speaker notes should be visible to all viewers
        showNotes: false,

        // Number of milliseconds between automatically proceeding to the
        // next slide, disabled when set to 0, this value can be overwritten
        // by using a data-autoslide attribute on your slides
        autoSlide: 0,

        // Stop auto-sliding after user input
        autoSlideStoppable: true,

        // Enable slide navigation via mouse wheel
        mouseWheel: true,

        // Hides the address bar on mobile devices
        hideAddressBar: true,

        // Opens links in an iframe preview overlay
        previewLinks: false,

        // Transition style
        transition: 'convex', // none/fade/slide/convex/concave/zoom

        // Transition speed
        transitionSpeed: 'default', // default/fast/slow

        // Transition style for full page slide backgrounds
        backgroundTransition: 'default', // none/fade/slide/convex/concave/zoom

        // Number of slides away from the current that are visible
        viewDistance: 3,

        // Parallax background image
        parallaxBackgroundImage: '', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"

        // Parallax background size
        parallaxBackgroundSize: '', // CSS syntax, e.g. "2100px 900px"

        // Number of pixels to move the parallax background per slide
        // - Calculated automatically unless specified
        // - Set to 0 to disable movement along an axis
        parallaxBackgroundHorizontal: null,
        parallaxBackgroundVertical: null,

				// Optional reveal.js plugins
				dependencies: [
					{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
					{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
					{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
					{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
					{ src: 'plugin/zoom-js/zoom.js', async: true },
					{ src: 'plugin/notes/notes.js', async: true }
				]
			});

		</script>

	</body>
</html>
